package cn.snowsoft.iot.module.cps.service.cpsRule;

import cn.hutool.core.util.ObjectUtil;
import cn.snowsoft.iot.module.cps.controller.admin.cpsRule.vo.CpsRulePageVO;
import cn.snowsoft.iot.module.cps.controller.admin.cpsRule.vo.CpsActionOutputVO;
import cn.snowsoft.iot.module.cps.controller.admin.cpsRule.vo.CpsDataEntryVO;
import cn.snowsoft.iot.module.cps.controller.admin.cpsRule.vo.CpsRuleSaveVO;
import cn.snowsoft.iot.module.cps.controller.admin.cpsRule.vo.DeviceProductVO;
import cn.snowsoft.iot.module.cps.dal.dataobject.cpsRule.CpsRule;
import cn.snowsoft.iot.module.cps.dal.dataobject.equipment.EquipmentDO;
import cn.snowsoft.iot.module.cps.dal.dataobject.equipment.EquipmentPointDO;
import cn.snowsoft.iot.module.cps.dal.dataobject.product.ProductDO;
import cn.snowsoft.iot.module.cps.dal.mysql.cpsRule.CpsRuleServiceMapper;
import cn.snowsoft.iot.module.cps.mqtt.MqttRule;
import cn.snowsoft.iot.module.cps.service.equipment.EquipmentService;
import cn.snowsoft.iot.module.cps.service.product.ProductService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import okhttp3.ResponseBody;

import java.util.Random;

import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
public class CpsRuleServiceImpl extends ServiceImpl<CpsRuleServiceMapper, CpsRule> implements CpsRuleService {
    @Autowired
    private EquipmentService equipmentService;
    @Autowired
    private ProductService productService;
    /**
     * 删除规则
     *
     * @param rulesCode
     * @return
     */
    @Override
    public Boolean mqttDeleteRules(String rulesCode) {
        try {
            MqttRule.deleteRules(rulesCode);
        } catch (Exception exception) {
            throw new RuntimeException(exception);
        }
        return null;
    }

    /**
     * 查询列表规则
     *
     * @param cpsRulePageVO
     * @return
     */
    @Override
    public IPage<CpsRulePageVO> selectcpsRulePage(CpsRulePageVO cpsRulePageVO) {
        IPage<EquipmentPointDO> page = new Page<>(cpsRulePageVO.getPageNo(), cpsRulePageVO.getPageSize());
        return baseMapper.selectCpsRulePage(page, cpsRulePageVO);
    }

    /**
     * 启用或者失效
     *
     * @param ruleCode
     * @param isEnabled
     * @return
     * @throws IOException
     */
    @Override
    public Boolean enabledOrDisabledRules(List<Long> id, List<String> ruleCode, Integer isEnabled) throws IOException {
        List<ProductDO> productList = productService.lambdaQuery().in(ProductDO::getProductCode, ruleCode).list();
        Map<String, ProductDO> productDOMap = productList.stream().collect(Collectors.toMap(e -> e.getProductCode(), e -> e));
        List<EquipmentDO> equipmentDOList = equipmentService.lambdaQuery().in(EquipmentDO::getProductCode, ruleCode).eq(EquipmentDO::getIsEnable, 1).list();
        Map<String, List<EquipmentDO>> stringListMap = equipmentDOList.stream().collect(Collectors.groupingBy(e -> e.getProductCode()));
        List<String> distinctProductCodeList = ruleCode.stream().distinct().collect(Collectors.toList());
        distinctProductCodeList.stream().forEach(e -> {
            List<EquipmentDO> equipmentDOList1 = stringListMap.get(e);
            if (ObjectUtil.isNotEmpty(equipmentDOList1) && equipmentDOList1.size() == 1) {
                ProductDO productDO = productDOMap.get(e);
                id.add(productDO.getId());
            }
        });
        List<CpsRule> cpsRuleList = lambdaQuery().in(CpsRule::getRelevanceId, id).list();
        List<CpsRule> cpsRuleArrayList = new ArrayList<>();
        cpsRuleList.stream().forEach(e -> {
            CpsRule cpsRule = new CpsRule();
            if (ObjectUtil.isEmpty(e.getRuleCode())) {
                e.setRuleCode(code(e.getRuleType()));
            }
            BeanUtils.copyProperties(e, cpsRule);
            cpsRuleArrayList.add(cpsRule);
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                List<CpsDataEntryVO> cpsDataEntryList = new ArrayList<>();
                if(ObjectUtils.isNotEmpty(e.getRuleInput())){
                    cpsDataEntryList = objectMapper.readValue(e.getRuleInput(), new TypeReference<List<CpsDataEntryVO>>() {
                    });
                }
                List<CpsActionOutputVO> cpsActionOutputVOS = new ArrayList<>();
                if (ObjectUtils.isNotEmpty(e.getAction())) {
                    cpsActionOutputVOS = objectMapper.readValue(e.getAction(), new TypeReference<List<CpsActionOutputVO>>() {
                    });
                }
                ResponseBody responseBody = MqttRule.getRule(e.getRuleCode());
                MqttRule.insertOrEditRule(transformationStructure(e, cpsDataEntryList, cpsActionOutputVOS, ObjectUtil.equals(1, isEnabled)), responseBody);
            } catch (JsonProcessingException ex) {
                throw new RuntimeException(ex);
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        });
        updateBatchById(cpsRuleArrayList);
        return true;
    }

    @Override
    public CpsRuleSaveVO submit(CpsRuleSaveVO cpsRuleSaveVO) {
        if (cpsRuleSaveVO.getId() != null) {
            CpsRule cpsRule = lambdaQuery().eq(CpsRule::getId, cpsRuleSaveVO.getId()).one();
            if (!cpsRule.getRuleType().equals(cpsRuleSaveVO.getRuleType())) {
                cpsRuleSaveVO.setId(null);
            }
        }
        cpsRuleSaveVO.setIsEnable("1");
        try {
            if (ObjectUtils.isNotEmpty(cpsRuleSaveVO.getCpsDataEntries())) {
                cpsRuleSaveVO.getCpsDataEntries().stream().forEach(e -> e.setId(generateRandom10DigitNumber()));
                ObjectMapper cpsDataEntriesMapper = new ObjectMapper();
                cpsRuleSaveVO.setRuleInput(cpsDataEntriesMapper.writeValueAsString(cpsRuleSaveVO.getCpsDataEntries()));
            }
            if (ObjectUtils.isNotEmpty(cpsRuleSaveVO.getCpsActionOutputs())) {
                ObjectMapper cpsActionOutputsMapper = new ObjectMapper();
                cpsRuleSaveVO.getCpsActionOutputs().stream().forEach(e -> e.setId(generateRandom10DigitNumber()));
                cpsRuleSaveVO.setAction(cpsActionOutputsMapper.writeValueAsString(cpsRuleSaveVO.getCpsActionOutputs()));
            }
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        saveOrUpdate(cpsRuleSaveVO);
        return cpsRuleSaveVO;
    }

    /**
     * 生成随机的 10 位数字 UUID
     *
     * @return
     */
    public static String generateRandom10DigitNumber() {
        StringBuilder sb = new StringBuilder(10);
        Random random = new Random();
        for (int i = 0; i < 10; i++) {
            sb.append(random.nextInt(10));
        }
        return sb.toString();
    }

    /**
     * 用于产品和设备调用
     *
     * @param deviceProductVO
     */
    @Override
    public void saveOrUpdateRule(DeviceProductVO deviceProductVO) {
        List<CpsRule> cpsRuleList = lambdaQuery().eq(CpsRule::getRelevanceId, deviceProductVO.getId()).list();
        if (ObjectUtils.isEmpty(cpsRuleList)) {
            deviceProductVO.getCpsRuleSaveVO().setId(null);
        }
        deviceProductVO.getCpsRuleSaveVO().setIsEnable("1");
        try {
            deviceProductVO.getCpsRuleSaveVO().setRelevanceId(deviceProductVO.getId());
            if (ObjectUtils.isNotEmpty(deviceProductVO.getCpsRuleSaveVO().getCpsDataEntries())) {
                deviceProductVO.getCpsRuleSaveVO().getCpsDataEntries().stream().forEach(e -> e.setId(generateRandom10DigitNumber()));
                ObjectMapper cpsDataEntriesMapper = new ObjectMapper();
                deviceProductVO.getCpsRuleSaveVO().setRuleInput(cpsDataEntriesMapper.writeValueAsString(deviceProductVO.getCpsRuleSaveVO().getCpsDataEntries()));
            }
            if (ObjectUtils.isNotEmpty(deviceProductVO.getCpsRuleSaveVO().getCpsActionOutputs())) {
                ObjectMapper cpsActionOutputsMapper = new ObjectMapper();
                deviceProductVO.getCpsRuleSaveVO().getCpsActionOutputs().stream().forEach(e -> e.setId(generateRandom10DigitNumber()));
                deviceProductVO.getCpsRuleSaveVO().setAction(cpsActionOutputsMapper.writeValueAsString(deviceProductVO.getCpsRuleSaveVO().getCpsActionOutputs()));
            }
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        saveOrUpdate(deviceProductVO.getCpsRuleSaveVO());
    }

    private Map<String, Object> transformationStructure(CpsRule one, List<CpsDataEntryVO> cpsDataEntryList, List<CpsActionOutputVO> cpsActionOutputList, Boolean isEnabled) {
        Map<String, Object> map = new HashMap<>();
        map.put("name", "");
        map.put("id", one.getRuleCode());
        map.put("sql", one.getRuleSql());
        map.put("enable", isEnabled);
        //备注
        map.put("description", "数据来源1.产品2.设备3.规则:"+one.getRuleType()+"---1上报2下发:"+one.getType());
        map.put("metadata", new HashMap<>());
        List<Object> list = new ArrayList<>();
        // 添加第二个 action: republish
        if (ObjectUtils.isNotEmpty(cpsActionOutputList)) {
            for (CpsActionOutputVO action : cpsActionOutputList) {
                Map<String, Object> republishAction = new HashMap<>();
                Map<String, String> args = new HashMap<>();
                args.put("payload", ObjectUtils.isNotEmpty(action.getPayload()) ? action.getPayload() : "${payload}");
                args.put("topic", action.getActionTheme());
                republishAction.put("args", args);
                republishAction.put("function", convertType(action.getActionType()));
                list.add(republishAction);
            }
        }
        // 将 actions 添加到主 Map
        map.put("actions", list);
        return map;
    }

    private String convertType(String actionType) {
        switch (actionType) {
            case "1":
                return "republish";
            default:
                return "republish";
        }
    }

    //生成编码
    private String code(String ruleType) {
//        1.产品2.设备3.规则
        switch (ruleType) {
            case "1":
                return "Product-" + UUID.randomUUID().toString().replace("-", "").substring(0, 8);
            case "3":
                return "Equipment-" + UUID.randomUUID().toString().replace("-", "").substring(0, 8);
            case "2":
                return "Rule-" + UUID.randomUUID().toString().replace("-", "").substring(0, 8);
            default:
                return "";
        }
    }
}